package com.mistone.cs;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * 描述
 *
 * @author mistone
 * @version 1.0
 * @created
 **/
public class AppConfigFileBeanPostProcess implements ResourcePatternResolver, BeanPostProcessor {
    private static final String[] DEFAULT_SEARCH_LOCATIONS = new String[]{"file:./config/","file:./","classpath:/config/","classpath:/"};
    private ApplicationContext applicationContext;
    private String[] searchLocations;

    public AppConfigFileBeanPostProcess(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        searchLocations = getLocationsFinal();
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 偷梁换柱
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this);
        }
        return bean;
    }


    /**
     * 查找spring.config.location和spring.config.additional-location配置
     * @return
     */
    private Set<String> getSearchLocations() {
        if (applicationContext.getEnvironment().containsProperty(ConfigFileApplicationListener.CONFIG_LOCATION_PROPERTY)) {
            return getSearchLocations(ConfigFileApplicationListener.CONFIG_LOCATION_PROPERTY);
        }
        Set<String> locations = getSearchLocations(ConfigFileApplicationListener.CONFIG_ADDITIONAL_LOCATION_PROPERTY);
        return locations;
    }

    /**
     * 处理参数
     * @param propertyName
     * @return
     */
    private Set<String> getSearchLocations(String propertyName) {
        Set<String> locations = new LinkedHashSet<>();
        if (applicationContext.getEnvironment().containsProperty(propertyName)) {
            for (String path : asResolvedSet(applicationContext.getEnvironment().getProperty(propertyName), null)) {
                if (!path.contains("$")) {
                    path = StringUtils.cleanPath(path);
                    if (!ResourceUtils.isUrl(path)) {
                        path = ResourceUtils.FILE_URL_PREFIX + path;
                    }
                }
                locations.add(path);
            }
        }
        return locations;
    }

    /**
     * 和默认配置进行合并
     * @return
     */
    private String[] getLocationsFinal(){
      Set<String> sets =   getSearchLocations();
      Set<String> floderSets = new LinkedHashSet<>();
      // 只做目录级别支持
      sets.forEach((name)->{
          if(name.endsWith("/")){
              floderSets.add(name);
          }
      });
      floderSets.addAll(Arrays.asList(DEFAULT_SEARCH_LOCATIONS));
      return floderSets.toArray(new String[0]);
    }

    /**
     * 处理参数，并反转
     * @param value
     * @param fallback
     * @return
     */
    private Set<String> asResolvedSet(String value, String fallback) {
        List<String> list = Arrays.asList(StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(
                (value != null) ? applicationContext.getEnvironment().resolvePlaceholders(value) : fallback)));
        Collections.reverse(list);
        return new LinkedHashSet<>(list);
    }

    @Override
    public Resource getResource(String location) {

        // 交个spring处理
        if(location==null||location.startsWith("classpath:")||location.startsWith("file:")||location.startsWith("/"))
        {
            return applicationContext.getResource(location);
        }else{
            Resource resource;
            // 查找并加工一下
            for(String path:searchLocations){
                resource = applicationContext.getResource(path+location);
                if(resource.exists()){
                    return resource;
                }
            }
            return applicationContext.getResource(location);
        }
    }

    @Override
    public ClassLoader getClassLoader() {
        return applicationContext.getClassLoader();
    }

    /**
     * 不对正则的进行处理了
     * @param locationPattern
     * @return
     * @throws IOException
     */
    @Override
    public Resource[] getResources(String locationPattern) throws IOException {
        return applicationContext.getResources(locationPattern);
    }
}
